﻿using Abp.Authorization;
using Microsoft.EntityFrameworkCore;
using Mt.Site.Application.AccessStatistics.Dto;
using Mt.Site.Core.AccessStatistics.Permissions;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Mt.Site.Application.AccessStatistics
{
    //来源分析模块
    partial class VisitStatisticAppService
    {
        // 全部来源
        [AbpAuthorize(ASPermissions.Pages_Manage_AccessStatistics_Query)]
        public async Task<SourceAnalysisOut> GetAllSourceAnalysis(SourceAnalysisInput input)
        {
            var startTime = input.StartTime;
            var endTime = input.EndTime;
            
            if (!_visitStatisticHelper.CheckTimeFormat(ref startTime, ref endTime))
            {
                return null;
            }
            input.StartTime = input.StartTime;
            input.EndTime = input.EndTime;
            var sourceAnalysisDto = new SourceAnalysisOut();
            sourceAnalysisDto.StartTime = startTime.ToString("yyyy-MM-dd");
            sourceAnalysisDto.EndTime = endTime.ToString("yyyy-MM-dd");
            sourceAnalysisDto.IpNum = 0;
            sourceAnalysisDto.AvgVisitTime = "";
            sourceAnalysisDto.NewNum = 0;
            sourceAnalysisDto.OutRate = 0;
            sourceAnalysisDto.PvNum = 0;
            sourceAnalysisDto.UvNum = 0;
            var outNumber = 0;
            var lengthOfStay = 0;
            var TenancyName = GetCurrentTenant().TenancyName;
            var IpQuery = from dataTwo in
                              from data in _AccessDataRespository.GetAll()
                              .AllSourceAnalysisQuery(input, TenancyName)
                              group data by new { Ip = data.ClientIp, SourceType = data.SourceType } into t
                              select new
                              {
                                  IpNum = t.Key.Ip,
                                  SourceType = t.Key.SourceType
                              }
                          group dataTwo by new { SourceType = dataTwo.SourceType } into tTwo
                          select new
                          {
                              IpNum = tTwo.Count(item => item.IpNum != null && item.IpNum != ""),
                              SourceType = tTwo.Key.SourceType
                          };

            var query = from dataTwo in
                            from data in _AccessDataRespository.GetAll()
                                    .AllSourceAnalysisQuery(input, TenancyName)
                            group data by new { Account = data.Acount, SourceType = data.SourceType } into t
                            select new
                            {
                                Account = t.Key.Account,
                                SourceType = t.Key.SourceType,
                                PvNum = t.Count(),
                                OutNum = t.Sum(item => item.IsBounced),
                                LengthOfStay = t.Sum(item => item.LengthOfStay),
                                newNum = t.Sum(item => item.IsNewVisitor)
                            }
                        group dataTwo by new { SourceType = dataTwo.SourceType } into tTwo
                        select new
                        {
                            UvNum = tTwo.Count(item => item.Account != null && item.Account != ""),
                            SourceType = tTwo.Key.SourceType,
                            PvNum = tTwo.Sum(item => item.PvNum),
                            OutNum = tTwo.Sum(item => item.OutNum),
                            LengOfStay = tTwo.Sum(item => item.LengthOfStay),
                            NewNum = tTwo.Sum(item => item.newNum)
                        };
            var ipList = await IpQuery.ToListAsync();

            var list = await query.ToListAsync();

            var sourceDataItems = new List<SourceDataItem>();
            foreach (var item in list)
            {
                var sourceItem = new SourceDataItem();
                sourceItem.SourceType = item.SourceType;
                sourceItem.PvNum = item.PvNum;
                sourceItem.UvNum = item.UvNum;
                sourceItem.NewNum = item.NewNum;
                sourceItem.LengthOfStay = item.LengOfStay;
                sourceItem.OutRate = _visitStatisticHelper.BounceRateCalc(item.OutNum, item.PvNum);
                sourceItem.AvgVisitTime = _visitStatisticHelper.NumberToTime(item.LengOfStay, item.PvNum, item.OutNum);

                sourceAnalysisDto.PvNum += item.PvNum;
                sourceAnalysisDto.UvNum += item.UvNum;
                sourceAnalysisDto.NewNum += item.NewNum;
                outNumber += item.OutNum;
                lengthOfStay += item.LengOfStay;

                sourceDataItems.Add(sourceItem);
            }
            foreach (var item in sourceDataItems)
            {
                foreach (var ipItem in ipList)
                {
                    if (item.SourceType == ipItem.SourceType)
                    {
                        item.IpNum = ipItem.IpNum;
                        sourceAnalysisDto.IpNum += item.IpNum;
                    }
                }
            }
            sourceAnalysisDto.OutRate = _visitStatisticHelper.BounceRateCalc(outNumber, sourceAnalysisDto.PvNum);
            sourceAnalysisDto.AvgVisitTime = _visitStatisticHelper.NumberToTime(lengthOfStay, sourceAnalysisDto.PvNum, outNumber);
            sourceAnalysisDto.Y_axis = sourceDataItems;
            return sourceAnalysisDto;
                         

        }

        //搜索引擎
        [AbpAuthorize(ASPermissions.Pages_Manage_AccessStatistics_Query)]
        public async Task<SourceSearchEngineOut> GetSerachEngineAnalysis(SourceSearchEngineInput input)
        {
            var startTime = input.StartTime;
            var endTime = input.EndTime;
            if (!_visitStatisticHelper.CheckTimeFormat(ref startTime,ref endTime)){
                return null;
            }
            var searcheEngineDto = new SourceSearchEngineOut();
            input.StartTime = startTime;
            input.EndTime = endTime;
            searcheEngineDto.StartTime = startTime.ToString("yyyy-MM-dd");
            searcheEngineDto.EndTime = endTime.ToString("yyyy-MM-dd");
            searcheEngineDto.AvgVisitTime = "00:00:00";
            searcheEngineDto.IpNum = 0;
            searcheEngineDto.NewNum = 0;
            searcheEngineDto.OutRate = 0;
            searcheEngineDto.PvNum = 0;
            searcheEngineDto.UvNum = 0;
            var outNumber = 0;
            var lengthOfStay = 0;
            var TenancyName = GetCurrentTenant().TenancyName;
            var ipQuery = from dataTwo in
                              from data in _AccessDataRespository.GetAll()
                              .SearchEngineAnalysisQuery(input, TenancyName)
                              group data by new { Ip = data.ClientIp, EngineType = data.EngineType } into t
                              select new
                              {
                                  Ip = t.Key.Ip,
                                  EngineType = t.Key.EngineType
                              }
                          group dataTwo by new { EngineType = dataTwo.EngineType } into tTwo
                          select new
                          {
                              IpNum = tTwo.Count(item => item.Ip != null && item.Ip != ""),
                              EngineType = tTwo.Key.EngineType
                          };

            var query = from dataTwo in
                            from data in _AccessDataRespository.GetAll()
                            .SearchEngineAnalysisQuery(input, TenancyName)
                            group data by new { EngineType = data.EngineType, Accout = data.Acount } into t
                            select new
                            {
                                Account = t.Key.Accout,
                                EngineType = t.Key.EngineType,
                                PvNum = t.Count(),
                                outNum = t.Sum(item => item.IsBounced),
                                newNum = t.Sum(item => item.IsNewVisitor),
                                LengthOfStay = t.Sum(item => item.LengthOfStay)
                            }
                        group dataTwo by new { EngineType = dataTwo.EngineType } into tTwo
                        select new {
                            UvNum = tTwo.Count(item=>item.Account != null && item.Account != ""),
                            PvNum = tTwo.Sum(item=>item.PvNum),
                            newNum = tTwo.Sum(item=>item.newNum),
                            outNum = tTwo.Sum(item=>item.outNum),
                            LengthOfStay = tTwo.Sum(item=>item.LengthOfStay),
                            EngineType = tTwo.Key.EngineType
                        };

            var ipList = await ipQuery.ToListAsync();
            var list = await query.ToListAsync();

            var searchEngineList = new List<SourceSearchEngineItem>();
            foreach (var item in list)
            {
                var engineItemDto = new SourceSearchEngineItem();
                engineItemDto.SerachEngine = item.EngineType;
                engineItemDto.UvNum = item.UvNum;
                engineItemDto.PvNum = item.PvNum;
                engineItemDto.NewNum = item.newNum;
                engineItemDto.LengthOfStay = item.LengthOfStay;
                engineItemDto.OutRate = _visitStatisticHelper.BounceRateCalc(item.outNum, item.PvNum);
                engineItemDto.AvgVisitTime = _visitStatisticHelper.NumberToTime(item.LengthOfStay, item.PvNum, item.outNum);

                searcheEngineDto.UvNum += item.UvNum;
                searcheEngineDto.PvNum += item.PvNum;
                searcheEngineDto.NewNum += item.newNum;
                lengthOfStay += item.LengthOfStay;
                outNumber += item.outNum;
                searchEngineList.Add(engineItemDto);
            }

            foreach (var item in searchEngineList)
            {
                foreach (var p in ipList)
                {
                    if (item.SerachEngine == p.EngineType)
                    {
                        item.IpNum = p.IpNum;
                        searcheEngineDto.IpNum += p.IpNum;
                    }
                }
            }

            searcheEngineDto.OutRate = _visitStatisticHelper.BounceRateCalc(outNumber, searcheEngineDto.PvNum);
            searcheEngineDto.AvgVisitTime = _visitStatisticHelper.NumberToTime(lengthOfStay, searcheEngineDto.PvNum, outNumber);
            searcheEngineDto.Y_axis = searchEngineList;
            return searcheEngineDto;
        }


        // 搜索词
        [AbpAuthorize(ASPermissions.Pages_Manage_AccessStatistics_Query)]
        public async Task<SourceSearchKeyOut> GetSearchKeyAnalysis(SourceSearchKeyInput input)
        {
            var startTime = input.StartTime;
            var endTime = input.EndTime;
            if (!_visitStatisticHelper.CheckTimeFormat(ref startTime, ref endTime))
            {
                return null;
            }
            var searcheKeyDto = new SourceSearchKeyOut();
            input.StartTime = startTime;
            input.EndTime = endTime;
            searcheKeyDto.StartTime = startTime.ToString("yyyy-MM-dd");
            searcheKeyDto.EndTime = endTime.ToString("yyyy-MM-dd");
            searcheKeyDto.AvgVisitTime = "00:00:00";
            searcheKeyDto.IpNum = 0;
            searcheKeyDto.NewNum = 0;
            searcheKeyDto.OutRate = 0;
            searcheKeyDto.PvNum = 0;
            searcheKeyDto.UvNum = 0;
            var outNumber = 0;
            var lengthOfStay = 0;
            var TenancyName = GetCurrentTenant().TenancyName;
            var ipQuery = from dataTwo in
                              from data in _AccessDataRespository.GetAll()
                              .SearchKeyAnalysisQuery(input, TenancyName)
                              group data by new { Ip = data.ClientIp, Searchkey = data.Searchkey } into t
                              select new
                              {
                                  Ip = t.Key.Ip,
                                  Searchkey = t.Key.Searchkey
                              }
                          group dataTwo by new { Searchkey = dataTwo.Searchkey } into tTwo
                          select new
                          {
                              IpNum = tTwo.Count(item => item.Ip != null && item.Ip != ""),
                              Searchkey = tTwo.Key.Searchkey
                          };

            var query = from dataTwo in
                            from data in _AccessDataRespository.GetAll()
                            .SearchKeyAnalysisQuery(input, TenancyName)
                            group data by new { Searchkey = data.Searchkey, Accout = data.Acount } into t
                            select new
                            {
                                Account = t.Key.Accout,
                                Searchkey = t.Key.Searchkey,
                                PvNum = t.Count(),
                                outNum = t.Sum(item => item.IsBounced),
                                newNum = t.Sum(item => item.IsNewVisitor),
                                LengthOfStay = t.Sum(item => item.LengthOfStay)
                            }
                        group dataTwo by new { Searchkey = dataTwo.Searchkey } into tTwo
                        select new
                        {
                            UvNum = tTwo.Count(item => item.Account != null && item.Account != ""),
                            PvNum = tTwo.Sum(item => item.PvNum),
                            newNum = tTwo.Sum(item => item.newNum),
                            outNum = tTwo.Sum(item => item.outNum),
                            LengthOfStay = tTwo.Sum(item => item.LengthOfStay),
                            Searchkey = tTwo.Key.Searchkey
                        };

            var ipList = await ipQuery.ToListAsync();
            var list = await query.ToListAsync();

            var searchKeyList = new List<SearchKeyItem>();
            foreach (var item in list)
            {
                var searchKeyItem = new SearchKeyItem();
                searchKeyItem.SerachKey = item.Searchkey;
                searchKeyItem.UvNum = item.UvNum;
                searchKeyItem.PvNum = item.PvNum;
                searchKeyItem.NewNum = item.newNum;
                searchKeyItem.LengthOfStay = item.LengthOfStay;
                searchKeyItem.OutRate = _visitStatisticHelper.BounceRateCalc(item.outNum, item.PvNum);
                searchKeyItem.AvgVisitTime = _visitStatisticHelper.NumberToTime(item.LengthOfStay, item.PvNum, item.outNum);

                searcheKeyDto.UvNum += item.UvNum;
                searcheKeyDto.PvNum += item.PvNum;
                searcheKeyDto.NewNum += item.newNum;
                lengthOfStay += item.LengthOfStay;
                outNumber += item.outNum;
                
                foreach (var p in ipList)
                {
                    if (item.Searchkey == p.Searchkey)
                    {
                        searchKeyItem.IpNum = p.IpNum;
                        searcheKeyDto.IpNum += p.IpNum;
                    }
                }
                searchKeyList.Add(searchKeyItem);
            }


            searcheKeyDto.OutRate = _visitStatisticHelper.BounceRateCalc(outNumber, searcheKeyDto.PvNum);
            searcheKeyDto.AvgVisitTime = _visitStatisticHelper.NumberToTime(lengthOfStay, searcheKeyDto.PvNum, outNumber);
            searcheKeyDto.SearchKeyItems = searchKeyList;
            return searcheKeyDto;
        }

        // 外链
        [AbpAuthorize(ASPermissions.Pages_Manage_AccessStatistics_Query)]
        public async Task<SourceExternalLinkOut> GetExternalLinkAnalysis(SourceExternalLinkInput input)
        {
            var startTime = input.StartTime;
            var endTime = input.EndTime;
            if (!_visitStatisticHelper.CheckTimeFormat(ref startTime, ref endTime))
            {
                return null;
            }
            var externalLinkDto = new SourceExternalLinkOut();
            input.StartTime = startTime;
            input.EndTime = endTime;
            externalLinkDto.StartTime = startTime.ToString("yyyy-MM-dd");
            externalLinkDto.EndTime = endTime.ToString("yyyy-MM-dd");
            externalLinkDto.AvgVisitTime = "00:00:00";
            externalLinkDto.IpNum = 0;
            externalLinkDto.NewNum = 0;
            externalLinkDto.OutRate = 0;
            externalLinkDto.PvNum = 0;
            externalLinkDto.UvNum = 0;
            var outNumber = 0;
            var lengthOfStay = 0;
            var TenancyName = GetCurrentTenant().TenancyName;
            var ipQuery = from dataTwo in
                              from data in _AccessDataRespository.GetAll()
                              .ExternalLinkAnalysisQuery(input, TenancyName)
                              group data by new { Ip = data.ClientIp, RefererUrl = data.RefererUrl } into t
                              select new
                              {
                                  Ip = t.Key.Ip,
                                  RefererUrl = t.Key.RefererUrl
                              }
                          group dataTwo by new { RefererUrl = dataTwo.RefererUrl } into tTwo
                          select new
                          {
                              IpNum = tTwo.Count(item => item.Ip != null && item.Ip != ""),
                              RefererUrl = tTwo.Key.RefererUrl
                          };

            var query = from dataTwo in
                            from data in _AccessDataRespository.GetAll()
                            .ExternalLinkAnalysisQuery(input, TenancyName)
                            group data by new { RefererUrl = data.RefererUrl, Accout = data.Acount } into t
                            select new
                            {
                                Account = t.Key.Accout,
                                RefererUrl = t.Key.RefererUrl,
                                PvNum = t.Count(),
                                outNum = t.Sum(item => item.IsBounced),
                                newNum = t.Sum(item => item.IsNewVisitor),
                                LengthOfStay = t.Sum(item => item.LengthOfStay)
                            }
                        group dataTwo by new { RefererUrl = dataTwo.RefererUrl } into tTwo
                        select new
                        {
                            UvNum = tTwo.Count(item => item.Account != null && item.Account != ""),
                            PvNum = tTwo.Sum(item => item.PvNum),
                            newNum = tTwo.Sum(item => item.newNum),
                            outNum = tTwo.Sum(item => item.outNum),
                            LengthOfStay = tTwo.Sum(item => item.LengthOfStay),
                            RefererUrl = tTwo.Key.RefererUrl
                        };

            var ipList = await ipQuery.ToListAsync();
            var list = await query.ToListAsync();

            var ExternalLinkList = new List<ExternalLinkItem>();
            foreach (var item in list)
            {
                var externalLinkItem = new ExternalLinkItem();
                externalLinkItem.RefererUrl = item.RefererUrl;
                externalLinkItem.UvNum = item.UvNum;
                externalLinkItem.PvNum = item.PvNum;
                externalLinkItem.NewNum = item.newNum;
                externalLinkItem.LengthOfStay = item.LengthOfStay;
                externalLinkItem.OutRate = _visitStatisticHelper.BounceRateCalc(item.outNum, item.PvNum);
                externalLinkItem.AvgVisitTime = _visitStatisticHelper.NumberToTime(item.LengthOfStay, item.PvNum, item.outNum);

                externalLinkDto.UvNum += item.UvNum;
                externalLinkDto.PvNum += item.PvNum;
                externalLinkDto.NewNum += item.newNum;
                lengthOfStay += item.LengthOfStay;
                outNumber += item.outNum;

                foreach (var p in ipList)
                {
                    if (item.RefererUrl == p.RefererUrl)
                    {
                        externalLinkItem.IpNum = p.IpNum;
                        externalLinkDto.IpNum += p.IpNum;
                    }
                }
                ExternalLinkList.Add(externalLinkItem);
            }


            externalLinkDto.OutRate = _visitStatisticHelper.BounceRateCalc(outNumber, externalLinkDto.PvNum);
            externalLinkDto.AvgVisitTime = _visitStatisticHelper.NumberToTime(lengthOfStay, externalLinkDto.PvNum, outNumber);
            externalLinkDto.ExternalLinkItems = ExternalLinkList;
            return externalLinkDto;
        }
    }
}
